<!--
  可配置的滑块组件
  功能：
  1. 支持自定义标签项配置
  2. 支持不同类型内容的渲染（通过插槽）
  3. 支持组间切换，带有平滑过渡效果
  4. 支持触摸滑动，包括垂直和水平方向的判断
  5. 在边界位置支持组间切换
-->
<template>
  <div class="slider-container">
    <!-- 顶部标签栏 -->
    <div class="slider-header">
      <div class="section-tabs">
        <!-- 标签背景，用于显示当前选中标签的背景 -->
        <div
          class="tab-background"
          :style="{
            transform: `translateX(${tabOffsets[sectionIndex] || 0}px)`,
            width: `${tabWidths[sectionIndex] || 0}px`
          }"
        ></div>
        <!-- 标签项列表 -->
        <div
          v-for="(tab, index) in tabs"
          :key="index"
          :class="['tab-item', { active: sectionIndex === index }]"
          @click="switchToSection(index)"
          :ref="'tab-' + index"
        >
          <span class="tab-content">
            {{ tab.name }}
            <span v-if="tab.showCounter && sectionIndex === index" class="counter">
              ({{ itemIndex + 1 }}/{{ totalCount }})
            </span>
          </span>
        </div>
      </div>
    </div>
    <!-- 外层滑动容器，用于切换不同的内容组 -->
    <swiper
      ref="outerSwiper"
      :options="outerSwiperOptions"
      @slideChange="handleOuterSlideChange"
    >
      <swiper-slide v-for="(tab, sectionIndex) in tabs" :key="sectionIndex">
        <div class="slider-section">
          <!-- 内层滑动容器，用于切换当前组内的内容 -->
          <swiper
            :options="getInnerSwiperOptions(sectionIndex)"
            @slideChange="() => handleInnerSlideChange(sectionIndex)"
            @touchStart="() => handleTouchStart(sectionIndex)"
            @touchMove="handleTouchMove.bind(null, sectionIndex)"
            @touchEnd="() => handleTouchEnd(sectionIndex)"
            :ref="'innerSwiper-' + sectionIndex"
          >
            <swiper-slide v-for="(item, index) in tab.items" :key="index">
              <!-- 使用具名插槽渲染不同类型的内容 -->
              <slot
                :name="tab.type"
                :item="item"
                :index="index"
                :isActive="sectionIndex === index && itemIndex === index"
              >
                <!-- 默认插槽内容 -->
                <img
                  v-if="tab.type === 'image'"
                  :src="item"
                  :alt="'图片 ' + (index + 1)"
                  class="slide-image"
                >
              </slot>
            </swiper-slide>
          </swiper>
        </div>
      </swiper-slide>
    </swiper>
  </div>
</template>

<script>
import { Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'

export default {
  name: 'ImageSlider',
  components: {
    Swiper,
    SwiperSlide
  },
  props: {
    // 标签配置数组
    tabs: {
      type: Array,
      required: true,
      validator: (tabs) => {
        return tabs.every(tab => {
          return tab.name && tab.type && Array.isArray(tab.items)
        })
      }
    },
    // 是否显示计数器
    showCounter: {
      type: Boolean,
      default: true
    },
    // 当前选中的内容组索引
    sectionIndex: {
      type: Number,
      default: 0
    },
    // 当前内容索引
    itemIndex: {
      type: Number,
      default: 0
    }
  },
  computed: {
    // 获取当前选中的内容组
    currentTab() {
      return this.tabs[this.sectionIndex]
    },
    // 当前组内容总数
    totalCount() {
      return this.currentTab ? this.currentTab.items.length : 0
    }
  },
  data() {
    return {
      tabOffsets: [], // 标签偏移量数组
      tabWidths: [], // 标签宽度数组
      isTransitioning: false, // 是否正在过渡中
      touchStartX: 0, // 触摸开始的X坐标
      touchStartY: 0, // 触摸开始的Y坐标
      isSwiping: false, // 是否正在滑动
      isVerticalScrolling: false, // 是否正在垂直滚动
      shouldUpdateIndex: true, // 是否应该更新索引
      lastSectionIndex: 0, // 上一次的 section 索引
      // 外层滑动器配置
      outerSwiperOptions: {
        resistanceRatio: 0, // 阻力系数，0表示无阻力
        touchRatio: 0, // 触摸比率，0表示禁用触摸
        noSwiping: false, // 是否禁用滑动
        speed: 300 // 滑动速度
      }
    }
  },
  watch: {
    // 监听外部传入的 sectionIndex 变化
    sectionIndex: {
      handler(newIndex) {
        // 更新标签度量
        this.$nextTick(this.updateTabMetrics)

        // 更新所有 swiper 实例
        this.$nextTick(() => {
          // 确保外部 swiper 更新
          const outerSwiper = this.$refs.outerSwiper.$swiper
          if (outerSwiper) {
            outerSwiper.update()
            outerSwiper.updateSlides()
          }

          // 更新所有内部 swiper
          this.tabs.forEach((_, index) => {
            const swiperRef = this.$refs['innerSwiper-' + index]
            if (swiperRef && swiperRef[0]) {
              const swiper = swiperRef[0].$swiper
              swiper.update()
              swiper.updateSlides()

              // 如果是当前 section，设置正确的索引
              if (index === newIndex) {
                swiper.slideTo(this.itemIndex, 0)
              }
            }
          })
        })
      },
      immediate: true
    },
    // 监听外部传入的 itemIndex 变化
    itemIndex: {
      handler(newIndex) {
        if (!this.shouldUpdateIndex) {
          this.shouldUpdateIndex = true
          return
        }

        this.$nextTick(() => {
          const swiperRef = this.$refs['innerSwiper-' + this.sectionIndex]
          if (swiperRef && swiperRef[0]) {
            const swiper = swiperRef[0].$swiper
            swiper.slideTo(newIndex, 0)
          }
        })
      }
    },
    // 监听标签配置变化，更新标签度量
    tabs: {
      handler() {
        this.$nextTick(this.updateTabMetrics)
      },
      deep: true
    }
  },
  mounted() {
    this.updateTabMetrics()
    window.addEventListener('resize', this.updateTabMetrics)

    // 初始化所有 swiper 实例
    this.$nextTick(() => {
      // 确保外部 swiper 正确初始化并设置位置
      const outerSwiper = this.$refs.outerSwiper.$swiper
      if (outerSwiper) {
        outerSwiper.update()
        outerSwiper.updateSlides()
        outerSwiper.slideTo(this.sectionIndex, 0)
      }

      // 初始化所有内部 swiper
      this.tabs.forEach((_, index) => {
        const swiperRef = this.$refs['innerSwiper-' + index]
        if (swiperRef && swiperRef[0]) {
          const swiper = swiperRef[0].$swiper
          swiper.update()
          swiper.updateSlides()

          // 如果是当前 section，设置正确的索引
          if (index === this.sectionIndex) {
            swiper.slideTo(this.itemIndex, 0)
          }
        }
      })
    })
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.updateTabMetrics)
  },
  methods: {
    // 更新标签的位置和宽度信息
    updateTabMetrics() {
      this.tabOffsets = []
      this.tabWidths = []
      let currentOffset = 0

      this.tabs.forEach((_, index) => {
        const tabRef = this.$refs['tab-' + index]
        if (tabRef && tabRef[0]) {
          const tab = tabRef[0]
          const width = tab.offsetWidth
          this.tabOffsets.push(currentOffset)
          this.tabWidths.push(width)
          currentOffset += width
        }
      })
    },
    // 获取内层滑动器配置
    getInnerSwiperOptions(sectionIndex) {
      return {
        resistanceRatio: 0.85, // 阻力系数，0.85表示有一定阻力
        touchRatio: 1, // 触摸比率，1表示正常触摸
        threshold: 20, // 滑动阈值
        longSwipes: true, // 是否启用长滑动
        longSwipesRatio: 0.5, // 长滑动比例
        followFinger: true, // 是否跟随手指
        watchSlidesProgress: true, // 是否监控滑动进度
        observer: true, // 是否启用观察者
        observeParents: true, // 是否观察父元素变化
        speed: 300, // 滑动速度
        touchStartPreventDefault: false, // 是否阻止默认触摸行为
        touchMoveStopPropagation: false, // 是否阻止触摸传播
        slidesPerView: 1, // 每次显示的幻灯片数量
        spaceBetween: 10, // 幻灯片之间的间距
        resistance: true, // 是否启用阻力
        touchAngle: 45 // 触摸角度
      }
    },
    // 处理触摸开始事件
    handleTouchStart(sectionIndex) {
      console.log('handleTouchStart==');
      const swiperRef = this.$refs['innerSwiper-' + sectionIndex]
      if (!swiperRef || !swiperRef[0]) return

      const swiper = swiperRef[0].$swiper
      const touch = swiper.touches.startX
      this.touchStartX = touch
      this.touchStartY = swiper.touches.startY
      this.isSwiping = false
      this.isVerticalScrolling = false
    },
    // 处理触摸移动事件
    handleTouchMove(sectionIndex, event) {
      if (this.isTransitioning) return

      const swiperRef = this.$refs['innerSwiper-' + sectionIndex]
      console.log('swiperRef==',swiperRef);
      if (!swiperRef || !swiperRef[0]) return

      const swiper = swiperRef[0].$swiper
      const touch = swiper.touches.currentX
      const touchY = swiper.touches.currentY

      // 判断滑动方向
      if (!this.isSwiping) {
        const diffX = Math.abs(touch - this.touchStartX)
        const diffY = Math.abs(touchY - this.touchStartY)

        // 判断是否为垂直滚动
        if (diffY > diffX) {
          this.isVerticalScrolling = true
          return
        }

        this.isSwiping = true
      }

      if (this.isVerticalScrolling) return

      const diff = touch - this.touchStartX
      const isAtBeginning = swiper.isBeginning && diff > 0
      const isAtEnd = swiper.isEnd && diff < 0

      // 在边界位置时判断是否可以切换到相邻组
      if (isAtBeginning && sectionIndex > 0) {
        // 向右滑动且在第一张，且不是第一个section，允许切换到上一组
        if (Math.abs(diff) > 50) {
          swiper.allowTouchMove = false
          this.$refs.outerSwiper.$swiper.touchRatio = 1
        } else {
          swiper.allowTouchMove = true
          this.$refs.outerSwiper.$swiper.touchRatio = 0
        }
      } else if (isAtEnd && sectionIndex < this.tabs.length - 1) {
        // 向左滑动且在最后一张，且不是最后一个section，允许切换到下一组
        if (Math.abs(diff) > 50) {
          swiper.allowTouchMove = false
          this.$refs.outerSwiper.$swiper.touchRatio = 1
        } else {
          swiper.allowTouchMove = true
          this.$refs.outerSwiper.$swiper.touchRatio = 0
        }
      } else {
        swiper.allowTouchMove = true
        this.$refs.outerSwiper.$swiper.touchRatio = 0
      }
    },
    // 处理内层滑动器切换事件
    handleInnerSlideChange(sectionIndex) {
      if (this.isTransitioning) return

      const swiperRef = this.$refs['innerSwiper-' + sectionIndex]
      if (swiperRef && swiperRef[0]) {
        const swiper = swiperRef[0].$swiper
        // 更新当前索引
        this.$emit('update:itemIndex', swiper.activeIndex)

        this.$emit('slide-change', {
          sectionIndex,
          itemIndex: swiper.activeIndex,
          item: this.tabs[sectionIndex].items[swiper.activeIndex]
        })
      }
    },
    // 处理触摸结束事件
    handleTouchEnd(sectionIndex) {
      if (this.isTransitioning || this.isVerticalScrolling) return

      const swiperRef = this.$refs['innerSwiper-' + sectionIndex]
      if (!swiperRef || !swiperRef[0]) return

      const swiper = swiperRef[0].$swiper
      const touch = swiper.touches.currentX
      const diff = touch - this.touchStartX

      // 重置外部滑动器的触摸比率
      this.$refs.outerSwiper.$swiper.touchRatio = 0

      // 根据滑动距离判断是否切换组
      if (Math.abs(diff) > 50) { // 最小滑动距离
        if (swiper.isBeginning && diff > 0 && sectionIndex > 0) {
          // 向右滑动且在第一张，切换到上一组最后一张
          const prevSwiperRef = this.$refs['innerSwiper-' + (sectionIndex - 1)]
          if (prevSwiperRef && prevSwiperRef[0]) {
            const prevSwiper = prevSwiperRef[0].$swiper
            const prevLastIndex = prevSwiper.slides.length - 1
            this.shouldUpdateIndex = false
            this.$emit('update:itemIndex', prevLastIndex)
          }
          this.switchToSection(sectionIndex - 1, true)
        } else if (swiper.isEnd && diff < 0 && sectionIndex < this.tabs.length - 1) {
          // 向左滑动且在最后一张，切换到下一组第一张
          const nextSwiperRef = this.$refs['innerSwiper-' + (sectionIndex + 1)]
          if (nextSwiperRef && nextSwiperRef[0]) {
            const nextSwiper = nextSwiperRef[0].$swiper
            this.shouldUpdateIndex = false
            this.$emit('update:itemIndex', nextSwiper.activeIndex || 0)
          }
          this.switchToSection(sectionIndex + 1)
        }
      }

      swiper.allowTouchMove = true
      this.isSwiping = false
      this.isVerticalScrolling = false
    },
    // 处理外层滑动器切换事件
    handleOuterSlideChange() {
      console.log('handleOuterSlideChange==');
      const newIndex = this.$refs.outerSwiper.$swiper.activeIndex
      const isRightSwipe = newIndex < this.lastSectionIndex
      this.lastSectionIndex = newIndex
      
      this.$emit('update:sectionIndex', newIndex)
      
      // 确保内部 swiper 的索引正确更新
      this.$nextTick(() => {
        const swiperRef = this.$refs['innerSwiper-' + newIndex]
        if (swiperRef && swiperRef[0]) {
          const swiper = swiperRef[0].$swiper
          // 如果是向右滑动切换到上一组，使用最后一个索引
          if (isRightSwipe) {
            this.$emit('update:itemIndex', swiper.slides.length - 1)
          } else {
            // 如果是向左滑动切换到下一组，使用第一个索引
            this.$emit('update:itemIndex', 0)
          }
        }
      })

      this.$emit('section-change', {
        sectionIndex: newIndex,
        section: this.tabs[newIndex]
      })
    },
    // 切换到指定内容组
    switchToSection(index, goToEnd = false) {
      if (this.isTransitioning) return

      this.isTransitioning = true
      this.$emit('update:sectionIndex', index)
      this.$refs.outerSwiper.$swiper.slideTo(index, 300)

      this.$nextTick(() => {
        const swiperRef = this.$refs['innerSwiper-' + index]
        if (swiperRef && swiperRef[0]) {
          const swiper = swiperRef[0].$swiper
          const targetIndex = goToEnd ? swiper.slides.length - 1 : 0
          swiper.slideTo(targetIndex, 300)

          setTimeout(() => {
            this.isTransitioning = false
          }, 300)
        }
      })
    }
  }
}
</script>

<style scoped>
/* 滑块容器样式 */
.slider-container {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  position: relative;
}

/* 顶部标签栏样式 */
.slider-header {
  position: absolute;
  bottom: 10px;
  left: 0;
  right: 0;
  z-index: 10;
  padding: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none; /* 确保标签栏不遮挡底部控件 */
}

/* 内容组容器样式 */
.slider-section {
  position: relative;
  height: 400px;
  pointer-events: auto; /* 确保内容组可以正常交互 */
}

/* 图片样式 */
.slide-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 标签容器样式 */
.section-tabs {
  position: relative;
  display: inline-flex;
  background: rgba(51, 51, 51, 0.9);
  border-radius: 20px;
  padding: 3px;
}

/* 标签背景样式 */
.tab-background {
  position: absolute;
  top: 3px;
  height: calc(100% - 6px);
  background: white;
  border-radius: 17px;
  transition: all 0.3s ease;
  z-index: 1;
}

/* 标签项样式 */
.tab-item {
  position: relative;
  cursor: pointer;
  z-index: 2;
  padding: 6px 16px;
  white-space: nowrap;
}

/* 标签内容样式 */
.tab-content {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.8);
  font-size: 13px;
  transition: color 0.3s ease;
}

/* 计数器样式 */
.counter {
  margin-left: 4px;
  font-size: 12px;
  opacity: 0.9;
}

/* 激活状态标签样式 */
.tab-item.active .tab-content {
  color: #333;
}

/* 滑动器容器样式 */
.swiper-container {
  width: 100%;
  height: 100%;
}

@media (max-width: 768px) {
  /* 移动端样式调整 */
  .slider-container {
    max-width: 100%;
  }
  .slider-header {
    padding: 5px;
  }
  .tab-item {
    padding: 4px 12px;
  }
  .tab-content {
    font-size: 12px;
  }
  .slider-section {
    height: 300px;
  }
}
</style>
